/*
 * Author: Honrun
 */
#include "stm32f4xx_hal.h"
#include "stdio.h"
#include "stdint.h"
#include "DevicesFlash.h"


int8_t cFlashWriteDatas(uint32_t uiAddress, uint8_t *pucBuff, int32_t iLength)
{
    FLASH_EraseInitTypeDef EraseInitStruct = {0};
    uint32_t i = 0, SECTORError = 0, uiCnt = 0;
    uint16_t *pusDataAddress = (uint16_t *)pucBuff;
    int8_t cError = 0;

    if(iLength <= 0)
        return 1;

    /* Fill EraseInit structure*/
    EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;
    EraseInitStruct.VoltageRange  = FLASH_VOLTAGE_RANGE_3;
    EraseInitStruct.NbSectors     = 1;

    /* Unlock the Flash to enable the flash control register access *************/
    HAL_FLASH_Unlock();

    iLength >>= 1;
    /* Write Flash */
    for(i = 0; i < iLength; ++i)
    {
        if(uiAddress >= FLASH_USER_MAX_ADDR)
        {
            cError |= 2;
            break;
        }

        if(cFlashGetErasePosition(uiAddress) != -1)
        {
            EraseInitStruct.Sector = cFlashGetErasePosition(uiAddress);

            uiCnt = 10000;
            while((HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK) && (--uiCnt));

            if(uiCnt == 0)
            {
               printf("cFlashWriteDatas HAL_FLASHEx_Erase addr: 0x%08X error: %d!\r\n", (unsigned int)uiAddress, (int)SECTORError);
                cError |= 4;
                break;
            }
        }

        if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, uiAddress, *pusDataAddress++) != HAL_OK)
        {
           printf("cFlashWriteDatas HAL_FLASH_Program addr: 0x%08X error!\r\n", (unsigned int)uiAddress);
            cError |= 8;
            break;
        }
        uiAddress += 2;
    }

    /* Lock the Flash to disable the flash control register access (recommended
       to protect the FLASH memory against possible unwanted operation) *********/
    HAL_FLASH_Lock();

    return cError;
}

int8_t cFlashReadDatas(uint32_t uiAddress, uint8_t *pucBuff, int32_t iLength)
{
    if(iLength <= 0)
        return 1;

    if((uiAddress + iLength) >= FLASH_USER_MAX_ADDR)
        return 2;

    /* Read Flash */
    while((iLength--) > 0)
    {
        *pucBuff++ = *(volatile uint8_t*)uiAddress++;
    }

    return 0;
}

int8_t cFlashGetErasePosition(uint32_t Address)
{
    switch(Address)
    {
        case ADDR_FLASH_SECTOR_0: return FLASH_SECTOR_0;
        case ADDR_FLASH_SECTOR_1: return FLASH_SECTOR_1;
        case ADDR_FLASH_SECTOR_2: return FLASH_SECTOR_2;
        case ADDR_FLASH_SECTOR_3: return FLASH_SECTOR_3;
        case ADDR_FLASH_SECTOR_4: return FLASH_SECTOR_4;
        case ADDR_FLASH_SECTOR_5: return FLASH_SECTOR_5;
        case ADDR_FLASH_SECTOR_6: return FLASH_SECTOR_6;
        case ADDR_FLASH_SECTOR_7: return FLASH_SECTOR_7;
        case ADDR_FLASH_SECTOR_8: return FLASH_SECTOR_8;
        case ADDR_FLASH_SECTOR_9: return FLASH_SECTOR_9;
        case ADDR_FLASH_SECTOR_10: return FLASH_SECTOR_10;
        case ADDR_FLASH_SECTOR_11: return FLASH_SECTOR_11;

        default: break;
    }

    return -1;
}

uint32_t uiFlashGetPositionSize(uint32_t Address)
{
    switch(Address)
    {
        case ADDR_FLASH_SECTOR_0: return 16 * 1024;
        case ADDR_FLASH_SECTOR_1: return 16 * 1024;
        case ADDR_FLASH_SECTOR_2: return 16 * 1024;
        case ADDR_FLASH_SECTOR_3: return 16 * 1024;
        case ADDR_FLASH_SECTOR_4: return 64 * 1024;
        case ADDR_FLASH_SECTOR_5: return 128 * 1024;
        case ADDR_FLASH_SECTOR_6: return 128 * 1024;
        case ADDR_FLASH_SECTOR_7: return 128 * 1024;
        case ADDR_FLASH_SECTOR_8: return 128 * 1024;
        case ADDR_FLASH_SECTOR_9: return 128 * 1024;
        case ADDR_FLASH_SECTOR_10: return 128 * 1024;
        case ADDR_FLASH_SECTOR_11: return 128 * 1024;

        default: break;
    }

    return 0;
}

int8_t cFlashReadProtection(uint8_t NewState)
{
    FLASH_OBProgramInitTypeDef OBInit = {0};
    int8_t cError = 0;

    HAL_FLASHEx_OBGetConfig(&OBInit);
    /* 千万千万不要选择等级2 */
    if((NewState != DISABLE) && (OBInit.RDPLevel == OB_RDP_LEVEL_0))
        OBInit.RDPLevel = OB_RDP_LEVEL_1;
    else if((NewState == DISABLE) && (OBInit.RDPLevel != OB_RDP_LEVEL_0))
        OBInit.RDPLevel = OB_RDP_LEVEL_0;
    else
        return cError;


    /* Allow Access to option bytes sector */
    HAL_FLASH_OB_Unlock();

    /* Allow Access to Flash control registers and user Flash */
    HAL_FLASH_Unlock();

    OBInit.OptionType = OPTIONBYTE_RDP;
    cError |= HAL_FLASHEx_OBProgram(&OBInit);

    /* 使设置生效 */
    cError |= HAL_FLASH_OB_Launch();

    /* Prevent Access to option bytes sector */
    HAL_FLASH_OB_Lock();

    /* Disable the Flash option control register access (recommended to protect
    the option Bytes against possible unwanted operations) */
    HAL_FLASH_Lock();


    return cError;
}
